home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turnbull China Bikeride
/
Turnbull China Bikeride - Disc 1.iso
/
HENSA
/
MISC
/
SIOD.ARC
/
!Siod
/
Scm
/
pratt_scm
< prev
next >
Wrap
Lisp/Scheme
|
1993-03-01
|
6KB
|
301 lines
;; -*-mode:lisp-*-
;;
;; A simple Pratt-Parser for SIOD: 2-FEB-90, George Carrette, GJC@PARADIGM.COM
;; Siod version 2.4 may be obtained by anonymous FTP to BU.EDU (128.197.2.6)
;; Get the file users/gjc/siod-v2.4-shar
;;
;; COPYRIGHT (c) 1990 BY
;; PARADIGM ASSOCIATES INCORPORATED, CAMBRIDGE, MASSACHUSETTS.
;; See the source file SLIB.C for more information.
;;
;;
;; Based on a theory of parsing presented in:
;;
;; Pratt, Vaughan R., ``Top Down Operator Precedence,''
;; ACM Symposium on Principles of Programming Languages
;; Boston, MA; October, 1973.
;;
;; The following terms may be useful in deciphering this code:
;; NUD -- NUll left Denotation (op has nothing to its left (prefix))
;; LED -- LEft Denotation (op has something to left (postfix or infix))
;; LBP -- Left Binding Power (the stickiness to the left)
;; RBP -- Right Binding Power (the stickiness to the right)
;;
;;
;; Example calls
;;
;; (pl '(f [ a ] = a + b / c)) => (= (f a) (+ a (/ b c)))
;;
;; (pl '(if g [ a COMMA b ] then a > b else k * c + a * b))
;; => (if (g a b) (> a b) (+ (* k c) (* a b)))
;;
;; Notes:
;;
;; This code must be used with siod.scm loaded, in siod version 2.3
;;
;; For practical use you will want to write some code to
;; break up input into tokens.
(defvar *eof* (list '*eof*))
;;
(defun pl (l)
;; parse a list of tokens
(setq l (append l '($)))
(toplevel-parse (lambda (op arg)
(cond ((eq op 'peek)
(if l (car l) *eof*))
((eq op 'get)
(if l (pop l) *eof*))
((eq op 'unget)
(push arg l))))))
(defun peek-token (stream)
(stream 'peek nil))
(defun read-token (stream)
(stream 'get nil))
(defun unread-token (x stream)
(stream 'unget x))
(defun toplevel-parse (stream)
(if (eq *eof* (peek-token stream))
(read-token stream)
(parse -1 stream)))
(defun value-if-symbol (x)
(if (symbol? x)
(symbol-value x)
x))
(defun nudcall (token stream)
(if (symbol? token)
(if (get token 'nud)
((value-if-symbol (get token 'nud)) token stream)
(if (get token 'led)
(error 'not-a-prefix-operator token)
token)
token)
token))
(defun ledcall (token left stream)
((value-if-symbol (or (and (symbol? token)
(get token 'led))
(error 'not-an-infix-operator token)))
token
left
stream))
(defun lbp (token)
(or (and (symbol? token) (get token 'lbp))
200))
(defun rbp (token)
(or (and (symbol? token) (get token 'rbp))
200))
(defvar *parse-debug* nil)
(defun parse (rbp-level stream)
(if *parse-debug* (print `(parse ,rbp-level)))
(defun parse-loop (translation)
(if (< rbp-level (lbp (peek-token stream)))
(parse-loop (ledcall (read-token stream) translation stream))
(begin (if *parse-debug* (print translation))
translation)))
(parse-loop (nudcall (read-token stream) stream)))
(defun header (token)
(or (get token 'header) token))
(defun parse-prefix (token stream)
(list (header token)
(parse (rbp token) stream)))
(defun parse-infix (token left stream)
(list (header token)
left
(parse (rbp token) stream)))
(defun parse-nary (token left stream)
(cons (header token) (cons left (prsnary token stream))))
(defun parse-matchfix (token left stream)
(cons (header token)
(prsmatch (or (get token 'match) token)
stream)))
(defun prsnary (token stream)
(defun loop (l)
(if (eq? token (peek-token stream))
(begin (read-token stream)
(loop (cons (parse (rbp token) stream) l)))
(reverse l)))
(loop (list (parse (rbp token) stream))))
(defun prsmatch (token stream)
(if (eq? token (peek-token stream))
(begin (read-token stream)
nil)
(begin (defun loop (l)
(if (eq? token (peek-token stream))
(begin (read-token stream)
(reverse l))
(if (eq? 'COMMA (peek-token stream))
(begin (read-token stream)
(loop (cons (parse 10 stream) l)))
(error 'comma-or-match-not-found (read-token stream)))))
(loop (list (parse 10 stream))))))
(defun delim-err (token stream)
(error 'illegal-use-of-delimiter token))
(defun erb-error (token left stream)
(error 'too-many token))
(defun premterm-err (token stream)
(error 'premature-termination-of-input token))
(defmac (defprops form)
(defun loop (l result)
(if (null? l)
`(begin ,@result)
(loop (cddr l)
`((putprop ',(cadr form) ',(cadr l) ',(car l))
,@result))))
(loop (cddr form) nil))
(defprops $
lbp -1
nud premterm-err)
(defprops COMMA
lbp 10
nud delim-err)
(defprops ]
nud delim-err
led erb-err
lbp 5)
(defprops [
nud open-paren-nud
led open-paren-led
lbp 200)
(defprops if
nud if-nud
rbp 45)
(defprops then
nud delim-err
lbp 5
rbp 25)
(defprops else
nud delim-err
lbp 5
rbp 25)
(defprops -
nud parse-prefix
led parse-nary
lbp 100
rbp 100)
(defprops +
nud parse-prefix
led parse-nary
lbp 100
rbp 100)
(defprops *
led parse-nary
lbp 120)
(defprops =
led parse-infix
lbp 80
rbp 80)
(defprops **
lbp 140
rbp 139
led parse-infix)
(defprops :=
led parse-infix
lbp 80
rbp 80)
(defprops /
led parse-infix
lbp 120
rbp 120)
(defprops >
led parse-infix
lbp 80
rbp 80)
(defprops <
led parse-infix
lbp 80
rbp 80)
(defprops >=
led parse-infix
lbp 80
rbp 80)
(defprops <=
led parse-infix
lbp 80
rbp 80)
(defprops not
nud parse-prefix
lbp 70
rbp 70)
(defprops and
led parse-nary
lbp 65)
(defprops or
led parse-nary
lbp 60)
(defun open-paren-nud (token stream)
(if (eq (peek-token stream) '])
nil
(let ((right (prsmatch '] stream)))
(if (cdr right)
(cons 'sequence right)
(car right)))))
(defun open-paren-led (token left stream)
(cons (header left) (prsmatch '] stream)))
(defun if-nud (token stream)
(define pred (parse (rbp token) stream))
(define then (if (eq? (peek-token stream) 'then)
(parse (rbp (read-token stream)) stream)
(error 'missing-then)))
(if (eq? (peek-token stream) 'else)
`(if ,pred ,then ,(parse (rbp (read-token stream)) stream))
`(if ,pred ,then)))